package br.com.sysprova.model;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;

public class HttpRestUtil {

	// Nome das adições ao cabeçalho (.addHeader())
	// private static final String HMAC = "Hmac";
	// private static final String HAPI = "ApiKey";
	//
	// private static final String HMACSUFIXO = ServerConfig.getHMACCode();
	// private static final String APIVALUE = ServerConfig.APIVALUE;
	private HttpClient httpClient;

	private static HttpRestUtil httpRestUtil;

	private HttpRestUtil() {
		HttpParams httpParams = new BasicHttpParams();

		HttpConnectionParams.setConnectionTimeout(httpParams, 3000);

		httpClient = new DefaultHttpClient(httpParams);
	}

	public static HttpRestUtil getHttpRestUtil() {
		if (httpRestUtil == null) {
			httpRestUtil = new HttpRestUtil();
		}
		return httpRestUtil;
	}

	/**
	 * Método que faz uma requisição GET e retorna o resultado como String
	 * 
	 * @param url
	 *            - URL a ser conectada
	 * @return String - resultado em String
	 */
	public String getRESTFileContent(String url) {
		HttpEntity entity = null;
		try {
			URI uri = new URI(url);

			// Log.i("URL", url + " Uri " + uri.toASCIIString());
			// Log.i("httprest", "hmacsufixo e api"+HMACSUFIXO+" "+APIVALUE);
			// Log.i("httprest", "hmac e hapi"+HMAC+" "+HAPI);

			HttpProtocolParams.setUseExpectContinue(httpClient.getParams(),
					false);
			HttpGet httpGet;

			httpGet = new HttpGet(uri.toASCIIString());
			// httpGet.addHeader(HMAC, HMACSUFIXO);
			// httpGet.addHeader(HAPI, APIVALUE);

			HttpResponse response = httpClient.execute(httpGet);
			entity = response.getEntity();

			if (entity != null) {
				InputStream in = entity.getContent();
				String result = toString(in);
				return result;

			}
		} catch (URISyntaxException e1) {
			e1.printStackTrace();
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (entity != null) {
				try {
					entity.getContent().close();
				} catch (IllegalStateException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}

		return null;
	}

	/**
	 * Método que faz uma requisição GET para autenticação de Usuário e retorna
	 * o resultado como String
	 * 
	 * @param url
	 *            - URL a ser conectada
	 * @param senha
	 * @param matricula
	 * @return String - resultado em String
	 * 
	 */
	public String getRESTFileContentAuth(String url, String matricula, String senha) {
		HttpEntity entity = null;
		try {
			URI uri = new URI(url);

			HttpProtocolParams.setUseExpectContinue(httpClient.getParams(),
					false);
			HttpGet httpGet;

			httpGet = new HttpGet(uri.toASCIIString());

			// httpGet.addHeader(HMAC, HMACSUFIXO);
			// httpGet.addHeader(HAPI, APIVALUE);
			httpGet.addHeader("senha", senha);
			httpGet.addHeader("matricula", matricula);

			HttpResponse response = httpClient.execute(httpGet);
			entity = response.getEntity();
			String tipo =response.getFirstHeader("tipo").getValue();
			if (entity != null) {
				InputStream in = entity.getContent();
				String result = toString(in);
				result+="tipoDoObjeto="+tipo;
				return result;

			}
		} catch (URISyntaxException e1) {
			e1.printStackTrace();
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (entity != null) {
				try {
					entity.getContent().close();
				} catch (IllegalStateException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}

		return null;
	}

	/**
	 * Método para montar conexões com o WS
	 * 
	 * @param caminhoUrl
	 *            - URL em String
	 * @param tipoDeMetodo
	 *            - método HTTP
	 * @param tipoDeDado
	 *            - Informação do dado enviado
	 * @param outPut
	 *            - Informa se a conexão aceita saída
	 * @return Conexão com o WS
	 */
	@Deprecated
	public HttpURLConnection montaConexaoWS(String caminhoUrl,
			String tipoDeMetodo, String tipoDeDado, boolean outPut) {
		URL url;
		HttpURLConnection conexao = null;

		HttpUriRequest http;

		URI uri = null;
		try {
			uri = new URI(caminhoUrl);
		} catch (URISyntaxException e1) {
			e1.printStackTrace();
		}

		Map<String, Integer> metodos = new HashMap<String, Integer>();

		metodos.put("POST", 1);
		metodos.put("PUT", 2);
		metodos.put("DELETE", 3);

		switch (metodos.get(tipoDeMetodo)) {
		case 1:

			HttpPost httpPost;
			httpPost = new HttpPost(uri.toASCIIString());

			http = httpPost;
			http.addHeader("Content-type", tipoDeDado);
			break;
		case 2:

			HttpPut httpPut;
			httpPut = new HttpPut(uri.toASCIIString());

			http = httpPut;
			http.addHeader("Content-type", tipoDeDado);
			break;
		case 3:
			HttpDelete httpDelete;
			httpDelete = new HttpDelete(uri.toASCIIString());

			http = httpDelete;

			break;
		default:
			http = null;
			break;
		}
		// http.addHeader(HMAC, HMACSUFIXO);
		// http.addHeader(HAPI, APIVALUE);

		try {

			// Indica caminho da conexao
			url = new URL(caminhoUrl);

			// Monta obejto que irá fazer a conexao
			conexao = (HttpURLConnection) url.openConnection();

			// Parâmetros da requisição
			conexao.setRequestMethod(tipoDeMetodo);
			if (!tipoDeMetodo.equalsIgnoreCase("DELETE")) {
				conexao.addRequestProperty("Content-type", tipoDeDado);
			}
			// metodo que informa se este HttpURLConnection permite saida de
			// dados
			conexao.setDoOutput(outPut);
			conexao.connect();
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return conexao;
	}

	public Integer enviaDadosWS(String caminhoUrl, String tipoDeMetodo,
			String tipoDeDado, byte[] dados) {

		HttpUriRequest http;

		URI uri = null;
		try {
			uri = new URI(caminhoUrl);
		} catch (URISyntaxException e1) {
			e1.printStackTrace();
		}

		Map<String, Integer> metodos = new HashMap<String, Integer>();
		metodos.put("POST", 1);
		metodos.put("PUT", 2);
		metodos.put("DELETE", 3);

		ByteArrayEntity bae = null;
		if (dados != null) {
			bae = new ByteArrayEntity(dados);
		}

		switch (metodos.get(tipoDeMetodo)) {
		case 1:

			HttpPost httpPost;
			httpPost = new HttpPost(uri.toASCIIString());
			httpPost.setEntity(bae);

			http = httpPost;
			http.addHeader("Content-type", tipoDeDado);
			break;
		case 2:

			HttpPut httpPut;
			httpPut = new HttpPut(uri.toASCIIString());
			httpPut.setEntity(bae);

			http = httpPut;
			http.addHeader("Content-type", tipoDeDado);
			break;
		case 3:
			HttpDelete httpDelete;
			httpDelete = new HttpDelete(uri.toASCIIString());

			http = httpDelete;

			break;
		default:
			http = null;
			break;
		}
		// http.addHeader(HMAC, HMACSUFIXO);
		// http.addHeader(HAPI, APIVALUE);

		HttpResponse response = null;
		try {
			response = httpClient.execute(http);

		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		int inf = response.getStatusLine().getStatusCode();
		try {
			response.getEntity().getContent().close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return inf;
	}

	/**
	 * Método que envia dados para o WS
	 * 
	 * @param conexao
	 *            - Conexão para enviar dados
	 * @param dados
	 *            - Dados a serem enviados
	 */
	@Deprecated
	public void enviaDadosWS(HttpURLConnection conexao, byte[] dados) {
		// Envia dados para a saída da conexão
		try {
			conexao.getOutputStream().write(dados);
			conexao.getOutputStream().flush();

			// Recupera resposta
			if (conexao.getResponseMessage() != null) {
				System.out.println("Conexao " + conexao.getResponseMessage());
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		conexao.disconnect();
	}

	/**
	 * Método que exclui um objeto de acordo com a url e id
	 */
	@Deprecated
	public void excluir(HttpURLConnection conexao) {
		try {
			// Recupera resposta
			if (conexao.getResponseMessage() != null) {
				System.out.println("Conexao " + conexao.getResponseMessage());
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		conexao.disconnect();
	}

	public void enviarImagem(String caminhoUrl, File f) {

		HttpPost post = new HttpPost(caminhoUrl);

		// MultipartEntity multiPart = new
		// MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
		MultipartEntity multiPart = new MultipartEntity();
		multiPart.addPart("imagem", new FileBody(f));
		post.setEntity(multiPart);
		// post.addHeader(HMAC, HMACSUFIXO);
		// post.addHeader(HAPI, APIVALUE);

		try {
			httpClient.execute(post);
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Método que transforma bytes em String
	 * 
	 * @param is
	 *            -dados de entrada
	 * @return String - dados convertidos em String
	 * @throws IOException
	 */
	private String toString(InputStream is) throws IOException {
		byte[] bytes = new byte[1024];
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		int lidos;
		while ((lidos = is.read(bytes)) > 0) {
			baos.write(bytes, 0, lidos);
		}
		String result = new String(baos.toByteArray());
		is.close();
		return result;
	}
}
